local type, assert, error = type, assert, error
local loadfile = loadfile
local setfenv = setfenv

local loaded_files = {}

local env = ...

local priv_modules = {
	"strict", "gfx/"
}

-- TODO: This function need to be more sophisticated, ultimately include
-- all built-in (or otherwise privileged) modules.
-- It also must be impossible to mistake user modules as privileged.
local function is_priv(path)
	--return priv_modules[path] or false
	local native = filesystem.to_native(path)
	for _,p in ipairs(priv_modules) do
		local test = filesystem.to_native(p)
		if string.find(native, test, 1, true) == 1 then
			return true
		end
	end
	return false
end

function dofile_native(path, native)
	local f, err = loadfile(native)
	if not f then
		error("loadfile error: " .. err)
	end
	if not is_priv(path) then
		setfenv(f, env)
	end

	return f()
end

function require_native(path, native, tab, force_priv)
	native = native .. ".lua"

	--print("require2 called with native path " .. native)

	local return_table

	if tab then
		print("[SYS] Loading module " .. native)
		local f, err = loadfile(native)
		if not f then
			error("loadfile error: " .. err)
		end

		if not is_priv(path) then
			setfenv(f, env)
		end

		return_table = f(tab)
	else
		return_table = loaded_files[native]
		if not return_table then
			print("[SYS] Loading module " .. native)
			local f, err = loadfile(native)
			if not f then
				error("loadfile error: " .. err)
			end

			-- TODO: Detect recursive require which is not
			-- allowed at the moment.

			local table = {}
			--loaded_files[native] = table
			if not force_priv and not is_priv(path) then
				setfenv(f, env)
			end

			return_table = f(table)
			loaded_files[native] = return_table
			--print("[SYS] Module loaded, returned: ", return_table)
		else
			--print("[SYS] Module " .. native .. " already loaded, returned: ", return_table)
		end
	end

	assert(type(return_table) == "table", "Expected loader to return a table")
	return return_table
end

filesystem = require_native("filesystem", ".\\filesystem", nil, true)

function dofile(path)
	--local kind, native = filesystem.native_path(path)
	local native = filesystem.to_native(path)

	--print("dofile2 called with native path " .. native)

	return dofile_native(path, native)
end

function require(path, tab)
	--local kind, native = filesystem.native_path(path)
	local native = filesystem.to_native(path)

	return require_native(path, native, tab)
end
